package com.atguigu.java2;

import com.atguigu.java1.Person;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 调用运行时类中指定的结构:属性,方法,构造器
 */
public class ReflectionTest {

    /**
     * 建议不采用  获取属性
     *
     * @throws Exception
     */
    @Test
    public void testField() throws Exception {
        Class clazz = Person.class;
        //创建运行时类的对象
        Person p = (Person) clazz.newInstance();
        //获取指定的属性  要求运行时类属性声明为public
        //通常不采用此方式
        Field id = clazz.getField("age");
        //设置当前属性
        /**
         * set方法 参数1 指明设置那个对象的属性 参数2:将此属性值设置为多少
         */
        id.set(p, 1001);
        /**
         * 获取当前属性值
         * 参数 获取那个对象
         */
        int o = (int) id.get(p);
        System.out.println(o);
    }

    /**
     * 需要掌握
     *
     * @throws Exception
     */
    @Test
    public void testField1() throws Exception {
        Class clazz = Person.class;
        //创建运行时类的对象
        Person p = (Person) clazz.newInstance();

        //获取运行中类指定变量名的属性
        Field name = clazz.getDeclaredField("name");
        //暴力修改
        name.setAccessible(true);
        name.set(p, "tom");
        System.out.println(name.get(p));
    }

    /**
     * 如何操作运行是类中的制定方法  需要掌握
     */

    @Test
    public void testMethod() throws Exception {
        Class clazz = Person.class;
        //创建运行时类的对象
        Person p = (Person) clazz.newInstance();

        /**
         * 获取指定的某个方法 第一个值为方法名 第二个值为形参类型   为了防止方法重载
         */
        Method show = clazz.getDeclaredMethod("show", String.class);
        //invoke  参数1:方法调用者 参数2实参
        show.setAccessible(true);
        //invoke的返回值等于调用方法的返回值
        String result = (String) show.invoke(p, "中国");
        System.out.println(result);
        /**
         * 调用静态方法
         */
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        //如果调用运行时类的方法没有返回值,invoke返回为null
        showDesc.invoke(p);

    }

    /**
     * 调用运行时类指定的构造器
     */

    @Test
    public void testConstructor() throws Exception{
        Class clazz = Person.class;
        //创建运行时类的对象
        Person p = (Person) clazz.newInstance();

        //获取指定的构造器
        //getDeclaredConstructor  描述方法的形参指定类型
        Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);

        //2保证此构造器一定能访问

        declaredConstructor.setAccessible(true);
        //创建运行时类的对象
        Person tom = (Person)declaredConstructor.newInstance("Tom");
        System.out.println(tom.toString());
    }
}
